iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
AI & Data

30天帶你從零基礎到Python爬蟲系列 第 20

[Day20] 爬蟲實戰練習 - 從網路上抓圖片

  • 分享至 

  • xImage
  •  

今天要正式進入爬蟲啦~第一個練習是要去爬Google好手氣裡的圖片!

google好手氣在哪裡呢?其實就在平常其實就在平常在google首頁,中間有兩個方塊的右邊那個就是了!
https://ithelp.ithome.com.tw/upload/images/20220913/20140998NQR3GgCQss.png

一開始先講一下爬蟲的SOP好了,它的目的是要幫你找到正確的網址。

  1. 在網頁空白處按右鍵檢視原始碼(原始碼是最上面網址列的回覆)
  2. 確定你需要的東西有在原始碼裡(圖片、網址或文字)
    a. 如果在原始碼內: 直接從網址列找
    b. 如果不在原始碼內: 打開F12,在Network裡找

找正確網址

先從第一步來,看到原始碼後可以知道這裡只有六張圖片,但我們想要的不只六張,所以要去找隱藏網址。
https://ithelp.ithome.com.tw/upload/images/20220913/201409989eTdwDQO1E.png

打開F12後,滑動頁面會發現,Name的部分跳出越來越多的資料,代表它跟google要到更多的圖片。隨便選擇一個月份,再點到Preview的地方就可以看到每張圖片的網址,要注意到的是它外面是用中括號括起來的代表是一個list,而最前面0123就是索引值,每一個元素都是一個字典,這就是JSON格式(list+dict)

開始程式編寫

接著要匯入爬蟲必備的requests函式庫,由於它是第三方的所以要事先下載。接著輸入你要爬的網址,要記得並不是輸入上方的網址列,而是F12裡月份點進去Headers的Gerenal網址。再來用requests裡的get()方法送出網址並得到回應,這裡response的是一種檔案類型而不是單純的值,所以是print不出東西的。
https://ithelp.ithome.com.tw/upload/images/20220913/20140998UvuAWt8MU5.png

import requests

url = "https://www.google.com/doodles/json/2022/9?hl=zh-TW"
response = requests.get(url)

但我們希望拿到的資料是像網站上的一樣是list+dict,所以當拿到的資料型態不符合預期的時候,就是要來做型態轉換,可以直接用response.json將型態轉成json格式,不過必須原本就是這種格式不然會發生錯誤,但是既然要用這個功能,要記得import json函式庫,這個是Python內建的所以不需要像requests一樣另外先下載好。

import json

pics = response.json()

現在pics這個list裡面放的是一張一張的圖也是一個一個的字典,所以現在要做的第一個操作是把每一張圖的網址拿出來並下載它,既然要跑很多次當然就是用到迴圈。由於p的型態是字典,如果想取裡面的value(網址)就要呼叫它的key,也就是title這個欄位,第二個我需要高畫質版本的網址,不過可以看到它前面缺了https:,所以需要幫它補一下。
https://ithelp.ithome.com.tw/upload/images/20220913/20140998qyd1cG4mye.png

for p in pics:  # p的型態是字典
    print(p["title"])  # 列印圖片標題
    imgurl = "https:" + p["high_res_url"]  # 取得高畫質版本
    print(imgurl)
    print("-" * 30)  # 最後印個分隔線

列出網址後總要下載到本地端嘛,存檔總會需要路徑而且最後的副檔名要是圖片檔(.gif/.png),可以發現剛剛輸出的高畫質版本的網址最後就有副檔名,所以就直接把網址的最後一個部分拆下來,可以用split()方法,用"/"當作分隔符號。

for p in pics:
    print(p["title"])
    imgurl = "https:" + p["high_res_url"]
    print(imgurl)
    fn = imgurl.split("/")[-1]  # 把網址的最後一個部分拆下來
    print("-" * 30)  # 最後印個分隔線

這時候如果直接存檔,圖片檔是會存到和main.py同一層,這樣好亂,我想用一個資料夾把它們關起來。現在我要儲存的路徑會是dn/fn,資料夾下面的檔案的感覺,接著要記得再把網址送出才可以拿到一個一個圖片的網址,最後把圖片轉成二進制的資料寫進圖片檔裡。用with...as打開檔案的好處是不需要再寫f.close()關閉檔案,因為本身就已經有這個功能了。

dn = "doodles"  # 創建一個資料夾
if not os.path.exists(dn):  # 如果這個資料夾不存在
    os.makedirs(dn)  # 那就建立一個資料夾
    
for p in pics:
    print(p["title"])  # 列印圖片標題
    imgurl = "https:" + p["high_res_url"]  # 取得高畫質版本
    print(imgurl)
    fn = imgurl.split("/")[-1]  # 把網址的最後一個部分拆下來
    totalfn = dn + "/" + fn
    Simgurl = requests.get(imgurl, stream=True)  # 再次把圖片網址送出
    img = Simgurl.content  # 把圖片轉成二進制的
    with open(totalfn, "wb") as f:
        f.write(img)
    print("-" * 30)  # 最後印個分隔線

完整程式碼

import requests
import os  # 所有跟作業系統有關的函示庫
import json  # 內建的不需要額外下載

dn = "doodles"
if not os.path.exists(dn):  # 如果這個資料夾不存在
    os.makedirs(dn)  # 那就建立一個資料夾

url = "https://www.google.com/doodles/json/2022/9?hl=zh-TW"
response = requests.get(url)
pics = response.json()

for p in pics:
    print(p["title"])  # 列印圖片標題
    imgurl = "https:" + p["high_res_url"]  # 取得高畫質版本
    print(imgurl)
    fn = imgurl.split("/")[-1]  # 把網址的最後一個部分拆下來
    totalfn = dn + "/" + fn
    Simgurl = requests.get(imgurl, stream=True)  # 再次把圖片網址送出
    img = Simgurl.content  # 把圖片轉成二進制的
    with open(totalfn, "wb") as f:
        f.write(img)
    print("-" * 30)  # 最後印個分隔線

上一篇
[Day19] 爬蟲入門 - 巴哈姆特動畫瘋
下一篇
[Day21] 爬蟲必備工具 - BeautifulSoup
系列文
30天帶你從零基礎到Python爬蟲30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言